package model;

import java.util.*;
import pieces.*;
import players.*;

/**
 * This is the main model class of Chess. it houses the information necessary to run a game of chess and calls
 * on aspects of the {@link players} and {@link pieces} packages.
 * @author Sacha Best
 */
public class ChessBoard extends GridGame<Piece>
{
	/**
	 * These assignments represent the {@link ChessBoard.gameType} of any given ChessBoard.
	 */
	public static final int HUMAN_HUMAN = 1, HUMAN_WHITE_COMP = 2, HUMAN_BLACK_COMP = 3;
	/**
	 * These {@link players.Player} instance variables serve to control the game. They can be either 
	 * {@link players.HumanPlayer} or {@link players.ComputerPlayer}, and each has a color associated 
	 * with it that is used heavily in this class.
	 */
	private Player white, black, currentPlayer;
	/**
	 * These {@link java.util.ArrayList}s hold the {@link pieces.Piece} each {@link players.Player} has on this ChessBoard.
	 */
	private ArrayList<Piece> whitePieces, blackPieces;
	/**
	 * This pointer references the {@link piece.Piece} currently selected by a user in the view.
	 * It serves the purpose of providing the {@link chess.Controller} information about which piece
	 * is being examined by the user in the view.
	 */
	private Piece currentSelected;
	/**
	 * This int represents the type of game currently playing.
	 * @see the static final constants in the ChessBoard class
	 */
	private int gameType;
	/**
	 * This boolean values discerns whether or not the {@link players.ComputerPlayer}(s) playing is
	 * intelligent or not.
	 * @see {@link ChessBoard}
	 */
	private boolean smartComputer;
	
	
	private Stack<Move> moves;
	private Stack<Move> tempRedo;
	/**
	 * This constructor initializes a new chess game, assigning default values to every
	 * instance variable using a switch statement for the different gameTypes.
	 * @param gameType - the type of game currently playing.
	 * @param smartComputer - whether or not the {@link players.ComputerPlayer} is smart.
	 * Computer game is smart.
	 */
	public ChessBoard(int gameType, boolean smartComputer) 
	{
		super(8, 8);
		moves = new Stack<Move>();
		tempRedo = new Stack<Move>();
		whitePieces = new ArrayList<Piece>();
		blackPieces = new ArrayList<Piece>();
		this.smartComputer = smartComputer;
		this.gameType = gameType;
		layoutBoard();
		switch (gameType)
		{
		case HUMAN_HUMAN:
			white = new HumanPlayer(this, Player.WHITE);
			black = new HumanPlayer(this, Player.BLACK);
			this.currentPlayer = white;
			break;
		case HUMAN_WHITE_COMP:
			white = new HumanPlayer(this, Player.WHITE);
			black = new ComputerPlayer(this, Player.BLACK, smartComputer);
			this.currentPlayer = white;
			break;
		case HUMAN_BLACK_COMP:
			white = new ComputerPlayer(this, Player.WHITE, smartComputer);
			black = new HumanPlayer(this, Player.BLACK);
			this.currentPlayer = white;
			break;
		}
	}
	/**
	 * This method adds a {@link pieces.Piece} to the grid at a given {@link model.Location} loc. It also adds
	 * it to the correct {@link java.util.ArrayList} for its color's pieces.
	 * @param piece - the Piece to be added.
	 * @param loc - the Location at which to add the piece.
	 */
	@Override
	public String add(Piece piece, Location loc)
	{
		if (piece.getColor() == Player.WHITE)
			whitePieces.add(piece);
		else
			blackPieces.add(piece);
		return super.add(piece, loc);
	}
	/**
	 * This method moves a {@link pieces.Piece} at {@link model.Location} from to {@link model.Location} to.
	 * @param from - the {@link model.Location} at which the Piece currently resides.
	 * @param to - the {@link model.Location} to move the Piece to.
	 */
	@Override
	public boolean move(Location from, Location to)
	{
		getObjectAt(from).setLocation(to);
		return super.move(from, to);
	}
	/**
	 * This method accesses the {@link java.util.ArrayList} of {@link pieces.Piece} for the white player.
	 * @return - the list of white's pieces.
	 */
	public ArrayList<Piece> getWhitePieces()
	{
		return whitePieces;
	}
	/**
	 * This method accesses the {@link java.util.ArrayList} of {@link pieces.Piece} for the black player.
	 * @return - the list of black's pieces.
	 */
	public ArrayList<Piece> getBlackPieces()
	{
		return blackPieces;
	}
	/**
	 * This is the overarching setup method called by the constructor. It calls various
	 * other methods to assist is laying out the start of a chess game.
	 */
	private void layoutBoard()
	{
		add(new King(new Location(7, 4), this, Player.WHITE), new Location(7, 4));
		add(new Queen(new Location(7, 3), this, Player.WHITE), new Location(7, 3));
		add(new King(new Location(0, 4), this, Player.BLACK), new Location (0, 4));
		add(new Queen(new Location(0, 3), this, Player.BLACK), new Location(0, 3));
		layoutCommonPieces();
		layoutPawns();
	}
	/**
	 * This method places {@link pieces.Pawn}s for each player on the board.
	 */
	private void layoutPawns()
	{
		for (int col = 0; col < 8; col++)
		{
			Location blackPawnLoc = new Location(1, col);
			Location whitePawnLoc = new Location(6, col);
			add(new Pawn(blackPawnLoc, this, Player.BLACK), blackPawnLoc);
			add(new Pawn(whitePawnLoc, this, Player.WHITE), whitePawnLoc);
		}
	}
	/**
	 * This method places the remaining Pieces ({@link pieces.Knight}s, {@link pieces.Bishop}s, 
	 * {@link pieces.Rook}s) on the board.
	 */
	private void layoutCommonPieces()
	{
		for (int piece = 0; piece < 3; piece++)
		{
			Location blackLoc1 = new Location(0, piece);
			Location whiteLoc1 = new Location(7, piece);
			Location blackLoc2 = new Location(0, 7 - piece);
			Location whiteLoc2 = new Location(7, 7 - piece);
			if (piece == 0)
			{
				add(new Rook(blackLoc1, this, Player.BLACK), blackLoc1);
				add(new Rook(whiteLoc1, this, Player.WHITE), whiteLoc1);
				add(new Rook(blackLoc2, this, Player.BLACK), blackLoc2);
				add(new Rook(whiteLoc2, this, Player.WHITE), whiteLoc2);
			}
			else if (piece == 1)
			{
				add(new Knight(blackLoc1, this, Player.BLACK), blackLoc1);
				add(new Knight(whiteLoc1, this, Player.WHITE), whiteLoc1);
				add(new Knight(blackLoc2, this, Player.BLACK), blackLoc2);
				add(new Knight(whiteLoc2, this, Player.WHITE), whiteLoc2);
			}
			else if (piece == 2)
			{
				add(new Bishop(blackLoc1, this, Player.BLACK), blackLoc1);
				add(new Bishop(whiteLoc1, this, Player.WHITE), whiteLoc1);
				add(new Bishop(blackLoc2, this, Player.BLACK), blackLoc2);
				add(new Bishop(whiteLoc2, this, Player.WHITE), whiteLoc2);
			}
		}
	}
	/**
	 * This method simulates the end of one move. It changes the instance variable
	 * {@link ChessBoard.currentPlayer} to the other {@link players.Player}.
	 */
	public void changeColor()
	{
		if (currentPlayer.getColor() == Player.WHITE)
			currentPlayer = black;
		else
			currentPlayer = white;
	}
	/**
	 * This method handles input from a user and directs it to the {@link Players.Player} {@link ChessBoard.currentPlayer}.
	 * @param from - the {@link model.Location} to be moved from.
	 * @param to - the {@link model.Location} to be moved to.
	 * @return a String representing the result of the move. @see method {@link ChessBoard.completeAction}.
	 */
	public String[] processInput(Location from, Location to)
	{
		return currentPlayer.makeMove(from, to);
	}
	/**
	 * This method finalizes a move instigated by a {@link Players.Player} using {@link Players.makeMove} method.
	 * First, the method identifies the piece moving, verifies it is not null, and assures
	 * that the correct {@link Players.Player} initiated the move.
	 * 
	 * Next, the method checks for a castle (i.e. the Rook and King must be moved).
	 * If the move indeed is a castle, the method {@link ChessBoard.handleCastle} is called, and if a promotion occurs,
	 * the controller handles it. Then, if anything is in the first index of the returned String[], the method returns
	 * and the controller handles the case.
	 * 
	 * Finally, if the method does not return, it changes turns and checks if the other color is in check, checkmate, or if a stalemate
	 * occurs.
	 * @param from - the {@link model.Location} moved from
	 * @param to - the {@link model.Location} moved to
	 * @return a String[] with two indices: the first index contains the result of the move (i.e. the wrong player
	 * moved, etc.). The second index contains the {@link model.Location}s moved from and to, unless a castle is
	 * commanded, then the second index is null.
	 */
	public String[] completeAction(Location from, Location to)
	{
		tempRedo.clear();
		String[] returned = new String[2];
		Piece moving = getObjectAt(from);
		boolean castleNotify = false;
		Location notify = null;
		if (moving == null)
			returned[0] = "No piece";
		else if (moving.getColor() != currentPlayer.getColor())
			returned[0] = "Wrong Player";
		else if (moving instanceof King && Math.abs(from.getCol() - to.getCol()) == 2)
		{
			castleNotify = true;
			notify = handleCastle(currentPlayer.getColor(), (King) moving, to);
		}
		else if (moving instanceof Pawn && (to.getRow() == 0 || to.getRow() == 7))
		{
			returned[0] = "Promote";
			returned[1] = from.toString() + ", " + to.toString();
			addMove(from, to, getObjectAt(from), getObjectAt(to));
			move(from, to);
		}
		else
		{
			addMove(from, to, getObjectAt(from), getObjectAt(to));
			move(from, to);
		}
		if (returned[0] != null)
			return returned;
		
		changeColor();
		Piece inCheckResult = inCheck(currentPlayer.getColor());
		if (inCheckResult != null)
		{
			if (inCheckResult instanceof King || determineCheckmate())
				returned[0] = "Checkmate";
			else
				returned[0] = "Checked";
		}
		else if (stalemate())
			returned[0] = "Stalemate";
		else
		{
			if (castleNotify)
			{
				returned[0] = "Castle" + notify.toString();
				return returned;
			}
			returned[0] = "Moved";
		}
		returned[1] = from.toString() + ", " + to.toString();
		return returned;
	}
	/**
	 * This method determines whether or not a stalemate has occurred. A stalemate occurs in two cases:
	 * a color is NOT in check yet cannot move anywhere, or the same move is played by both colors for three
	 * turns in a row.
	 * @return true if a stalemate has occurred, false otherwise.
	 */
	private boolean stalemate()
	{
		if (determineCheckmate() && inCheck(currentPlayer.getColor()) == null)
			return true;
		boolean repetition = false;
		if (moves.size() >= 8)
		{
			ArrayList<Move> temp = new ArrayList<Move>(6);
			for (int count = 0; count < 8; count++)
				temp.add(moves.pop());
			Collections.reverse(temp);
			if (temp.get(0).equals(temp.get(4)) && temp.get(1).equals(temp.get(5))
			&& (temp.get(2).equals(temp.get(6))) && temp.get(3).equals(temp.get(7)))
				repetition = true;
			for (int count = 0; count < temp.size(); count++)
				moves.push(temp.get(count));
		}
		return repetition;
	}
	/**
	 * This method promotes a {@link piece.Pawn} that has reached the last row of the opposite side of the board
	 * to a piece described by the int to.
	 * @see constants in {@link pieces.Piece}
	 * @param pawn - the pawn to be promoted
	 * @param to - an int describing the {@link pieces.Piece} to be promoted to
	 */
	public void promote(Pawn pawn, int to)
	{
		Piece added = null;
		switch (to)
		{
		case pieces.Piece.BISHOP:
			added = new Bishop(pawn.getLocation(), this, pawn.getColor());
			break;
		case pieces.Piece.KNIGHT:
			added = new Knight(pawn.getLocation(), this, pawn.getColor());
			break;
		case pieces.Piece.ROOK:
			added = new Rook(pawn.getLocation(), this, pawn.getColor());
			break;
		case pieces.Piece.QUEEN:
			added = new Queen(pawn.getLocation(), this, pawn.getColor());
			break;
		}
		set(added, added.getLocation());
		if (added.getColor() == Player.WHITE)
			whitePieces.add(added);
		else
			blackPieces.add(added);
		changeColor();
	}
	/**
	 * This method determines whether or not the {@link ChessBoard.currentPlayer} has any available moved. In conjunction
	 * with {@link ChessBoard.inCheck}, this method can determine if a color has been checkmated.
	 * @return - true if {@link ChessBoard.currentPlayer} has no avaliable moves, false otherwise
	 */
	private boolean determineCheckmate()
	{
		ArrayList<Piece> currentPieces = whitePieces;
		if (currentPlayer.getColor() == Player.BLACK)
			currentPieces = blackPieces;
		for (Piece piece:currentPieces)
			if (piece.getLocation() != null && getObjectAt(piece.getLocation()) == piece && getMoveLocations(piece).size() > 0)
				return false;
		return true;
	}
	/**
	 * This method handles a castle for a given {@link pieces.King}. It moves the {@link pieces.King} to the given
	 * {@link model.Location} to and moves the accompanying {@link pieces.Rook} the appropriate amount of spaces.
	 * @param color - the color of the moving {@link pieces.King}
	 * @param king - the {@link pieces.King} to be moved
	 * @param to - the {@link model.Location} the {@link pieces.King} will be moved to.
	 * @return
	 */
	private Location handleCastle(int color, King king, Location to)
	{
		int kingToMove = 0, rookToMove = 0;
		ArrayList<Piece> currentPieceSet = null;
		Location rookLocation = null;
		int row = 0;
		currentPieceSet = blackPieces;
		if (color == Player.WHITE)
		{
			row = 7;
			currentPieceSet = whitePieces;
		}
		if (to.equals(new Location(row, 6)))
		{
			rookLocation = new Location(row, 7);
			kingToMove = 2;
			rookToMove = -2;
		}
		else
		{
			rookLocation = new Location(row, 0);
			kingToMove = -2;
			rookToMove = 3;
		}
		Location kingLocation = currentPieceSet.get(0).getLocation();
		move(kingLocation, new Location(kingLocation.getRow(), kingLocation.getCol() + kingToMove));
		move(rookLocation, new Location(rookLocation.getRow(), rookLocation.getCol() + rookToMove));
		return new Location(rookLocation.getRow(), rookLocation.getCol() + rookToMove);
	}
	/**
	 * This method determines whether or not a given color is in check. It is only public for use by the ComputerPlayer
	 * @param color - the color to examine
	 * @return the {@link pieces.Piece} causing check, null otherwise
	 */
	public Piece inCheck(int color)
	{
		int colorChecking = 0;
		King king;
		if (color == Player.WHITE)
		{
			colorChecking = Player.BLACK;
			king = (King) whitePieces.get(0);
		}
		else
		{
			colorChecking = Player.WHITE;
			king = (King) blackPieces.get(0);
		}
		ArrayList<Piece> checking = threatenedBy(king.getLocation(), colorChecking);
		if (checking.size() > 1)
			return new King(null, null, 0);
		else if (checking.size() == 0)
			return null;
		else
			return checking.get(0);
	}
	/**
	 * This method determines if a given {@link model.Location} is threatened by a given int color. It parses
	 * the ArrayList of {@link pieces.Piece}s for that color, and adds each {@link pieces.Piece} threatening
	 * that {@link model.Location} to a returned ArrayList
	 * @param loc - the {@link model.Location} to be checked
	 * @param color - the color of the {@link players.Player} to parse
	 * @return an ArrayList containing any and all {@link pieces.Piece}s threatening loc
	 */
	private ArrayList<Piece> threatenedBy(Location loc, int color)
	{
		ArrayList<Piece> inQuestion = blackPieces;
		if (color == Player.WHITE)
			inQuestion = whitePieces;
		ArrayList<Piece> threatening = new ArrayList<Piece>();
		for (Piece piece:inQuestion)
		{
			if (piece instanceof Pawn && getObjectAt(piece.getLocation()) == piece)
			{
				ArrayList<Location> pawnDanger = ((Pawn) piece).getThreateningLocations();
				for (Location pawn:pawnDanger)
					if (pawn.equals(loc))
						threatening.add(piece);
			}
			else if (getObjectAt(piece.getLocation()) == piece && piece.getMoveLocations().contains(loc)) //contains Pieces of same color for supporting
				threatening.add(piece);
		}
		return threatening;
	}
	/**
	 * This method filters the method {@link pieces.Piece.getMoveLocations} in the {@link pieces.Piece} class, removing
	 * all {@link model.Location}s that hold {@link pieces.Piece}s of the same color.
	 * @param piece - the {@link pieces.Piece} to check
	 * @return a semi-filtered ArrayList of that {@link pieces.Piece}'s possible move locations
	 */
	private ArrayList<Location> getSemiFilteredMoveLocations(Piece piece)
	{
		if (piece == null)
			return null;
		ArrayList<Location> tempLocs = piece.getMoveLocations();
		for (int count = tempLocs.size() - 1; count >= 0; count--)
		{
			Piece temp = getObjectAt(tempLocs.get(count));
			if (temp != null && temp.getColor() == piece.getColor())
				tempLocs.remove(count);
		}
		return tempLocs;
	}
	/**
	 * This is the overachring "move" method. It handles every case of a chess game: checks, pins, castles, etc.
	 * It filters the semi-filtered move locations of the parameter piece to its final state and returns it for use
	 * in the controller.
	 * @param piece - the {@link pieces.Piece} in question
	 * @return the final move locations of the given {@link pieces.Piece}
	 */
	public ArrayList<Location> getMoveLocations(Piece piece)
	{
		ArrayList<Location> tempLocs = getSemiFilteredMoveLocations(piece);
		if (tempLocs == null || piece == null)
			return null;
		Piece checking = inCheck(piece.getColor());
		King king = (King) whitePieces.get(0);
		if (piece.getColor() == Player.BLACK)
			king = (King) blackPieces.get(0);
		if (checking != null)
			return handleCheck(piece, checking, king);
		else if (!(piece instanceof King))
		{
			ArrayList<Location> pinResult = handlePin(piece, king);
			if (pinResult != null)
				return pinResult;
		}
		else
			return handleKingMoveLocations((King) piece, tempLocs);
		return tempLocs;
	}
	/**
	 * This method handle the move locations for a given {@link pieces.King} king. It mutates the parameter tempLocs
	 * based upon the current state of the board (checks, pins, etc.) because {@link pieces.King}s cause a special case
	 * of moving.
	 * @param king - the {@link pieces.King} in question
	 * @param tempLocs - the semi-filtered move locations for the king
	 * @return an ArrayList of possible move locations for the given {@link pieces.King}
	 */
	private ArrayList<Location> handleKingMoveLocations(King king, ArrayList<Location> tempLocs)
	{
		int otherColor = Player.WHITE;
		if (king.getColor() == Player.WHITE)
			otherColor = Player.BLACK;
		for (int count = tempLocs.size() - 1; count >= 0; count--)
		{
			if (threatenedBy(tempLocs.get(count), otherColor).size() > 0)
				tempLocs.remove(count);	
			else if (Math.abs(tempLocs.get(count).getCol() - king.getLocation().getCol()) == 2)
			{
				Location rookLoc = king.getLocation().getAdjacentLocation(Location.EAST).getAdjacentLocation(Location.EAST).getAdjacentLocation(Location.EAST);
				Rook rook = (Rook) getObjectAt(rookLoc);
				if (castleOverCheck(king, false) || rook == null || rook.hasMoved())
					tempLocs.remove(count);
			}
			else if (Math.abs(tempLocs.get(count).getCol() - king.getLocation().getCol()) == 3)
			{
				Location rookLoc = king.getLocation().getAdjacentLocation(Location.WEST).getAdjacentLocation(Location.WEST).getAdjacentLocation(Location.WEST)
						.getAdjacentLocation(Location.WEST);
				Rook rook = (Rook) getObjectAt(rookLoc);
				if (castleOverCheck(king, false) || rook == null || rook.hasMoved())
					tempLocs.remove(count);
			}
		}
		return tempLocs;
	}
	/**
	 * This method is called before a castle to determine if a given {@link pieces.King} will need to castle over threatened
	 * {@link model.Location}s, invalidating the castle.
	 * @param king - the {@link pieces.King} to check
	 * @param queenSide - a boolean describing the nature of the castle (queen side or normal)
	 * @return - true if the castle is invalid, false if it is valid
	 */
	private boolean castleOverCheck(King king, boolean queenSide)
	{
		int otherColor = Player.WHITE, direction = Location.EAST;
		if (king.getColor() == Player.WHITE)
			otherColor = Player.BLACK;
		if (queenSide)
			direction = Location.WEST;
		Location oneAway = king.getLocationInDirection(direction);
		Location twoAway = oneAway.getAdjacentLocation(direction);
		if (threatenedBy(oneAway, otherColor).size() > 0)
			return true;
		if (threatenedBy(twoAway, otherColor).size() > 0)
			return true;
		if (queenSide && threatenedBy(twoAway.getAdjacentLocation(direction), otherColor).size() > 0)
			return true;
		return false;
	}
	/**\
	 * This method alters a {@link pieces.Piece}'s move locations based on pins affected upon it. For example,
	 * if moving the parameter piece would cause a check for piece's {@link players.Player}, then that piece cannot
	 * move. This is handled by traversing the opponent's pieces and each one's move locations.
	 * @param piece - the {@link pieces.Piece} to check.
	 * @param yourKing - the {@link pieces.King} of piece's {@link players.Player}
	 * @return the revised ArrayList of move locations for piece
	 */
	private ArrayList<Location> handlePin(Piece piece, King yourKing)
	{
		ArrayList<Location> tempLocs = new ArrayList<Location>();
		if (inSamePlane(piece.getLocation(), yourKing.getLocation()))
		{
			boolean isPinned = false;
			ArrayList<Piece> theirPieceSet = blackPieces;
			ArrayList<Piece> yourPieceSet = whitePieces;
			if (piece.getColor() == Player.BLACK)
			{
				theirPieceSet = whitePieces;
				yourPieceSet = blackPieces;
			}
			for (Piece toCheck:theirPieceSet)
			{
				if ((toCheck instanceof Queen || toCheck instanceof Rook
				|| (toCheck instanceof Bishop))
				&& (getSemiFilteredMoveLocations(toCheck).contains(piece.getLocation()))
				&& (inBetween(piece.getLocation(), toCheck.getLocation(), yourKing.getLocation())))
				{
					isPinned = true;
					for (Piece possibleBlocker:yourPieceSet)
					{
						if ((!possibleBlocker.equals(piece))
						&& (inBetween(possibleBlocker.getLocation(), toCheck.getLocation(), yourKing.getLocation())))
							return null;
					}
					for (Location loc:getSemiFilteredMoveLocations(piece))
					{
						if (loc.equals(toCheck.getLocation()))
							tempLocs.add(loc);
						else if (inBetween(loc, yourKing.getLocation(), toCheck.getLocation()))
							tempLocs.add(loc);
					}
				}
			}
			if (isPinned)
				return tempLocs;
		}
		return null;
	}
	/**
	 * This method handles the check situation for a given {@link pieces.King}. It parses through toTry's move locations
	 * to see if any of the possible moves will resolve the check affected on the king by {@link pieces.Piece} checking.
	 * This method is only public for use by the ComputerPlayer.
	 * @param toTry - the {@link pieces.Piece} to block the check
	 * @param checking - the {@link pieces.Piece} causing the check
	 * @param king - the {@link pieces.King} in check
	 * @return an ArrayList of possible move locations for toTry based on the check
	 */
	public ArrayList<Location> handleCheck(Piece toTry, Piece checking, King king)
	{
		ArrayList<Location> tempLocs = getSemiFilteredMoveLocations(toTry);
		ArrayList<Location> resolving = new ArrayList<Location>();
		if (checking instanceof Knight || toTry instanceof King)
		{
			if (tempLocs.contains(checking.getLocation()) && !(toTry instanceof King))
				resolving.add(checking.getLocation());
			if (toTry instanceof King)
			{
				int otherColor = Player.WHITE;
				if (toTry.getColor() == Player.WHITE)
					otherColor = Player.BLACK;
				for (int count = tempLocs.size() - 1; count >= 0; count--)
				{
					if (threatenedBy(tempLocs.get(count), otherColor).size() > 0
					|| (Math.abs(toTry.getLocation().getCol() - tempLocs.get(count).getCol()) > 1))
						tempLocs.remove(count);
					else if ((checking instanceof Rook || checking instanceof Queen || checking instanceof Bishop)
						 && (inBetween(toTry.getLocation(), tempLocs.get(count), checking.getLocation())))
						 tempLocs.remove(count);
				}
				return tempLocs;
			}
		}
		for (Location loc:tempLocs)
			if ((inBetween(loc, king.getLocation(), checking.getLocation()) && (getSemiFilteredMoveLocations(checking).contains(loc)))
			|| loc.equals(checking.getLocation()))
				resolving.add(loc);
		return resolving;
	}
	/**
	 * Sets the currently selected {@link pieces.Piece} to piece
	 * @param piece - the new currently selected {@link pieces.Piece}
	 */
	public void selectPiece(Piece piece)
	{
		this.currentSelected = piece;
	}
	/**
	 * @return the currently selected {@link pieces.Piece}
	 */
	public Piece getSelectedPiece()
	{
		return currentSelected;
	}
	/**
	 * Deselects the currently selected {@link pieces.Piece}. This method is called by the controller to handle
	 * user clicks in the view.
	 */
	public void deselectPiece()
	{
		this.currentSelected = null;
	}
	/**
	 * This method is called by the controller in setting up the game board.
	 * @return an Object array holding the int representing the game type and a boolean representing the intelligence
	 * of the computer
	 */
	public Object[] getSettings()
	{
		Object[] passed = {gameType, smartComputer};
		return passed;
	}
	/**
	 * This method is ONLY called in setting up the game.
	 * @return the GridGame<E> holding the data of the game
	 */
	public Object[][] getGrid()
	{
		return grid;
	}
	/**
	 * @return the {@link players.Player} currently up to move
	 */
	public Player getCurrentPlayer()
	{
		return currentPlayer;
	}
	/**
	 * This method is called when moving to add a {@link model.Move} to the undo or redo stack.
	 * @param from - the {@link model.Location} moved from
	 * @param to - the {@link model.Location} moved to
	 * @param fromPiece - the {@link pieces.Piece} at from (can be null)
	 * @param toPiece - the {@link pieces.Piece} at to (can be null)
	 */
	public void addMove(Location from, Location to, Piece fromPiece, Piece toPiece)
	{
		moves.push(new Move(from, to, fromPiece, toPiece));
	}
	/**
	 * @return the last {@link model.Move} made, null if there are none
	 */
	public Move getUndo()
	{
		try
		{
			return tempRedo.push(moves.pop());
		}
		catch(EmptyStackException e)
		{
			return null;
		}
	}
	/**
	 * @return the last {@link model.Move} made, null if there are none
	 */
	public Move getRedo()
	{
		try
		{
			return moves.push(tempRedo.pop());
		}
		catch(EmptyStackException e)
		{
			return null;
		}
	}
	/**
	 * @return the white {@link players.Player}
	 */
	public Player getWhite()
	{
		return white;
	}
	/**
	 * @return the black {@link players.Player}
	 */
	public Player getBlack()
	{
		return black;
	}
}
